raFS


Technical Details

This part of the manual describes more technical aspects of raFS. It is not necessary for you to read it, but there are a few things here that aren't mentioned in the User Manual.


Corrupted discs

raFS includes code to deal as cleanly as possible with discs that contain invalid directories or file references. For example, a disc may become corrupted due to changed but not yet saved directory data being lost when the computer crashes.

Whenever directory data is loaded into memory, the filing system performs a number of checks to ensure that it really represents a valid directory - incorrect directories could have disastrous effects. An error message of the form directory data in 'ADFS::4.$.A0.A0.A0' is invalid is given in this case.

Before a new file or directory is written to the host filing system, raFS also ensures that the directory doesn't contain any files with invalid names. If a file is found whose name is not one of the 77 names A0 to Z1, the save operation fails with Name inside the directory containing a raFS disc is not of the form 'A0.A0.A0'

Finally, special code deals with files on raFS which refer to files on the host filing system that either don't exist or that have a different time/date stamp. If a file is missing, a dummy file (length zero, file type zero, date stamp 01-01-1900) is created to prevent other files from being assigned that ID. (Depending on the configured TimeZone of your machine, the year may also be displayed as 2248 instead of 1900.)

If the date stamp, file type or the file length does not match the directory entry, all open, load, save, delete and create operations on files will only produce an error like 'ADFS::4.$.A0.A0.A0' does not belong to this directory entry - verify the raFS disc. In this state, the only possible operations are renaming the file, stamping it (or changing its access details) and deleting it (only if it refers to a dummy file). Stamping the file causes the data to be synchronized, so that any operation can be applied to it again, but only do this if you are very sure about it!

Because there are filing systems that cannot store the date stamp in centiseconds like the native RiscOS filing systems do, the stamp will still be considered valid if it doesn't differ by more than 24 hours from what the raFS directory entry contains. Some filing systems don't allow file stamps at all. Consequently, it is possible to disable the checks by setting the system variable raFS$NoChecks to a comma-separated list of filing system names or image file types of the form &FC8 before mounting discs on those filing systems. The names are matched case-sensitively.

Back to the top of the page


Behaviour in special situations

There are a few points worth noting about how raFS behaves in certain situations.

Back to the top of the page


Limits of raFS

The following gives some information about the limits imposed by raFS on its discs. In practice. you are very unlikely to reach any of them, though.

Back to the top of the page


Known problems

Back to the top of the page


Command line interface

The raFSFiler module provides one *command:

Desktop_raFSFiler [-choices] [-newdisc] [-left] [-right] [-priority <nr>]
If issued without any arguments, this command causes raFS to install its icon on the icon bar. You can change the position of the icon bar icon by adding -left, -right and -priority switches to the command in the !Run file.

The -choices and -newdisc switches are useful for executing when the icon bar icon is clicked on. They open the "Choices" and "Create new disc" windows, respectively.

Desktop_raFSFiler also supports -options, -mount, -select and -adjust switches, but these are intended for internal use only.

raFS provides several *commands. While the raFSFiler module offers a more convenient way of working with discs, you may sometimes prefer to use the command line instead.

raFS
This command selects raFS as the current filing system. For raFS commands that are also supported by other filing systems, like Mount, you must switch to raFS with this command before using them. (Alternatively, you can use raFS:Mount to switch to raFS temporarily.)
raFS_Create <directory> <DiscName> [-app <SpriteName>]
This command sets up a storage directory for a disc, so that you can subsequently mount it with Mount <directory>. If you use a whole hard or floppy disc just for raFS, use the root directory "$" as the storage directory, otherwise choose a directory as near to the root as possible.

The storage directory is the directory to which all files saved to the disc will be written. If the specified directory does not already exist, it is created. If it isn't empty, raFS will give an error.

If the given directory's leafname begins with "!", the optional -app switch can be used to specify the name of a sprite to use for this application, for example -app directory to make it look like an ordinary directory. This sprite must be present in the Wimp's pool when the command is issued. raFS also saves a !Run file so that double-clicking on the application will mount the disc and open its root directory. The -app switch has no effect if the first character of the leafname is not "!".

To delete a complete raFS disc, make sure it has been dismounted and then Wipe the storage directory.

raFS_Flush
This command saves the directory information of any altered directories to the host filing system. However, in contrast to Dismount the cached directories remain in memory. It is useful to ensure that a subsequent crash will not cause data to be lost.
raFS_Discs
raFS_Discs or the equivalent raFS_Disks gives a list of all discs that are mounted at the time the command is entered. One line of text will be printed for each disc, consisting of the disc name followed by a space character and the name of the disc's storage directory.

Future versions of raFS may print out additional information after that described above, with further items appended to the printed lines after spaces. Take this into account when writing programs that make use of this command's output.

Mount <directory> [-readonly] [-path] [-X]
This command makes sure that you can access the raFS disc stored in the specified directory, e. g. that you can open the root directory "raFS::DiscName.$". It will also set the current directory to the disc's root directory, unset the User Root Directory (URD), and set the system variable raFS$Disc to the new disc's name.

Two discs with the same name cannot be mounted at the same time - an error will be given if this is attempted. However, if you try to mount a disc that is already mounted (i. e. the disc of that name has the same storage directory as specified in the Mount command), raFS will give no error and will ignore the command.

raFS automatically decides whether or not the disc is read-only by looking at the file !Atterer. If this file does not have write access (either because it resides on a read-only filing system or because you set its attributes in order to permanently "write protect" the disc), all attempts to modify files or directories will be faulted.

The optional -readonly switch (short -ro) write protects the disc even if !Atterer has write access.

Any -path switch appended to the command will only come into effect if the disc stored in the specified directory has the same name as one of the currently mounted discs. In this case, it is assumed that the name of that disc's storage directory has changed (e. g. because you renamed a directory in the path) and that raFS should update its workspace accordingly. Use this with care! You must not use this feature to set the path to the storage directory of a different disc!

When mounting discs without an -X switch appended to the Mount command, raFS looks for a file called !Mount in the storage directory. If the file is not present, the disc is just mounted, but if !Mount is found, it is Run. Apart from that, nothing happens; the disc is not mounted if !Mount is run. However, it can be an Obey file containing the command "raFS:Mount <Obey$Dir> -X". The presence of the -X switch indicates to raFS that the disc should be mounted without searching for !Mount. (Be careful not to create a loop by forgetting to add the -X switch!) With this system, it is possible to execute *commands before and after the disc is mounted.

Dismount [<DiscName>]
This command does the opposite of Mount, removing the specified disc (or all mounted discs if you omit the name) from its internal list and saving any cached directory data. Discs must always be dismounted before you reset or switch off the computer, but usually you don't need to use Dismount because raFS is automatically called when the desktop shuts down and when you issue Shutdown.

Note that in case raFS is RMKilled, it will try to dismount all discs. However, any errors while doing this will be ignored, and the module will not refuse to die, which means you lose data! It behaves like this because if it refused to be RMKilled, you would not be able to reload it unless you reset the machine.

Before a disc is dismounted, raFS sets the system variable raFS$DDisc to its name and tries to run any file called !Dismount residing in the storage directory. If errors occur during its execution, they are ignored; the disc is always dismounted. You must not dismount raFS discs in a !Dismount file. When the module is RMKilled, the !Dismount files are not executed.

NameDisc <OldDiscName> <NewDiscName>
This command (or also NameDisk) is used to change the name of a disc. Obviously, the disc must have been mounted for it to work.
Free
The Free command is just passed on to the host filing system that the currently selected raFS directory is stored on, e. g. if the disc is on ADFS, ADFS:Free will be executed.
raFS_Unsafe [-verbose]
By default, raFS only saves changed directory data to the host filing system after a delay. Usually, this is desirable because it is faster, but sometimes you may want to temporarily switch on write-through of the cache, so any changes are saved immediately. Instead of raFS_Opt -dd 1, you can also switch on write-through with this command.

The -verbose switch has the same functionality as for raFS_Safe below.

raFS_Safe [-smash] [-verbose]
This does the opposite of raFS_Unsafe, re-enabling the chosen delay values for saving directory cache contents. Note that an internal counter is kept, which means that in order to disable write-through after issuing raFS_Unsafe twice, you would also have to execute raFS_Safe twice. (After that, any additional raFS_Safe will have no effect.) If the number of raFS_Unsafe commands is unknown, you can use raFS_Safe -smash to disable write-through immediately.

A -verbose switch makes raFS print out the value of the internal counter after it has been modified.

raFS_Unsafe and raFS_Safe can be added to a Wimp application's !Run file if the application tends to crash the computer, in such a way that write-through is disabled once the application is quit:

other commands, e. g. WimpSlot, IconSprites etc.
raFS_Unsafe
Run <App$Dir>.!RunImage %*0
raFS_Safe

raFS_Opt [-DirCache <kB>] [-DirsaveDelay <cs>] [-DirsaveMods <nr>] [-DirUpcall 0|1] [-OpenRename 0|1] [-LoadMessages <name>]
This command is used to influence various miscellaneous aspects of raFS' behaviour, or to output the current settings if no parameters are given. Each of the optional keywords is followed by a value, in some cases just 0 or 1 to switch on and off. The keywords can be abbreviated to the characters written in uppercase, e. g. -dc instead of -DirCache. However, case doesn't matter on the command line; -dircache or -dC are the same as -DirCache.

Currently, the following keywords have an effect:

raFS_ExecAfter <centiseconds> <command line>
This command has little to do with raFS. It simply passes the specified command line to the CLI after the given delay. Due to the way this is achieved, only few commands can be used. Filer_Run is the only way to start a program using this command.

Back to the top of the page


Calling raFS from assembler

As of version 1.10, there is a way of calling certain routines inside the raFS module directly from assembler. raFSFiler uses these calls to get information about discs and current settings.

To call an raFS routine, you must first find out the address of the module workspace with:

    SYS "XOS_Module",18,"raFS" TO R0%,R1%,R2%,R3%,workspace%

Move the returned value into R11 before calling raFS with the following instructions:

    MOV LR,PC
    LDR PC,[R11,#rout_offset%]

If you use MOV LR,PC (and not ADD LR,PC,#0) before calling the routine, the N, Z and C flags will be preserved. When calling raFS from SVC code, you must use MOV, otherwise the processor will switch to USR mode once the call returns.

The rout_offset% is zero for the routine described first below, and increases in the order the routines are described. The Docs directory contains a small BASIC program which sets up the offsets with a horrible EVAL trick and which also provides a macro for the BASIC assembler so the above can be reduced to, e. g. FNcall(raFS_Info).

Registers not mentioned in "On exit" are preserved. (Of course, R14 is corrupted.) For all calls, R11 must point to the workspace of the raFS module. Processor must be in USR or SVC mode, R13 must point to a full descending stack with at least 1k free.

In the following descriptions, any bits in fields that are not described are reserved. It should not be assumed that they are zero, and when setting the word's value, they must be preserved.

raFS_Info
On entry:
-

On exit:
R0 = module version number * 100
R1 = maximum number of discs this version can have mounted
R2 = bit 0 set => module's heap is in sprite area, bits 24-31 = country number (1 for UK, 7 for Germany / as of V1.12, is always 1)
R3-R5 corrupted

Never returns an error.

raFS_NrOfDiscs
On entry:
-

On exit:
R0 = number of discs currently mounted

Never returns an error.

raFS_EnumerateDiscs
On entry:
R9 = -1 for first call

On exit:
R0 = word-aligned pointer to zero-terminated disc name
R1 = word-aligned pointer to unterminated name of storage directory
R2 = length of name of storage directory
R9 = disc number (also value of R9 for next call to this routine) or -1 and C set if no more discs

Never returns an error. The information must be copied away immediately; it may change during any call to raFS (except raFS_MemCopy) or accesses to the filing system.

After the disc name there are 1 to 4 zero bytes, up to the next word boundary, so you can find the length faster by first loading words and only looking at the high byte with TST Rx,#&FF<<24

raFS_FindDisc
On entry:
R1 => zero-terminated disc name

On exit:
R0 = word-aligned pointer to zero-terminated disc name
R1 = word-aligned pointer to unterminated name of storage directory
R2 = length of name of storage directory
R8 = internal ID of the disc's root directory
R9 = disc number
R14 = length of disc name

If a disc of the given name is not mounted, an error is returned. Again, the returned pointers to the disc name (whose case may differ from that passed to the routine) and storage directory are read-only and must be copied away immediately.

raFS_DiscInfo
On entry:
R9 = disc number

On exit:
R0 = word-aligned pointer to zero-terminated disc name
R1 = word-aligned pointer to unterminated name of storage directory
R2 = length of name of storage directory
R3 = flags:
    bit 0 set => the disc is read-only
    bit 1 set => integrity checks are performed (raFS$NoChecks)
R8 = internal ID of the disc's root directory
or C set if disc of that number not mounted

If the given disc number is in the valid range (zero to maximum number - 1) and a disc of that number does not exist, this returns with C set. Obviously, this call is much faster than raFS_FindDisc because it doesn't have to search for the disc name.

raFS_MemCopy
On entry:
R2 => source (word-aligned)
R3 => destination (word-aligned)
R4 = number of bytes to copy (multiple of 4)

On exit:
Registers preserved

The memory areas may overlap.

raFS_ReadVar
On entry:
R0 = number of variable to read

On exit:
R0 = value / pointer to string (depending on variable type)
R1 corrupted

Currently, the following variables are supported:

raFS_SetVar
On entry:
R0 = number of variable to set value of
R1 = new value

On exit:
R0, R1 corrupted

R0 on entry contains the same values as for raFS_ReadVar

Back to the top of the page


File formats

This section outlines the format of a raFS disc for the curious and for those who can't wait for me to implement Verify :-( In the following descriptions, an ID word is of the form &00zzyyxx where xx is the first level directory, yy the second, and zz the leaf name, e.g. &00010203 is the file 'B0.A2.A1'. The root directory is always 'A0.A0.A0'.

The !Atterer file

Size Description
64   disc name, null terminated, padded with zeroes
4    there is guaranteed no unused ID lower than this one
4    attribute flags for root directory (0 at present)
4    0 (unimplemented)
4    o = number of buffer settings following (always 0 at present)
??*o buffer settings

Directory format

Size Description
4    n = nr of entries
4    m = 0 (unimplemented)
4    ID of parent (max. 76.76.76.0) - word contains -1 for root
4    &80000000 (unimplemented)
4*n  offset to start of directory entries
     (words must be sorted in ascending order, file names in ASCII order,
     offsets are relative to start of these offsets)
4*m  if any, offset to... (unimplemented)
4    offset to first unused byte after dir entries/dir names (also from
     beginning of offsets, so that if there are no entries, this contains the
     value 4)

This is followed by the individual entries, if any:

4    load address
4    exec address
4    length (or FileSwitch handle if flag bit 12 set)
4    attributes
4    raFS attributes/flags:
     bits 0-1: 0 (unimplemented)
          2-3: 0 (unimplemented)
          4-5: 0 (unimplemented)
          6-7: 0=normal file, 1/2 unimplemented, 3=directory
          12:  if set, file is open => 'length' contains FileSwitch handle
4    0 (unimplemented)
4    ID of file/directory
4*?  name of file/directory, zero-terminated, padded with zeroes to the next
     multiple of 4.
4*?  (unimplemented, always null at present)

If an entry with bit 12 set is encountered upon loading directory data, raFS checks whether its own list of files contains that file ID together with the FileSwitch handle found in the directory entry. If there is no such entry in the list of open files, it is assumed that the machine crashed and the length is restored.

Back to the top of the page